{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练集数据 shape:  (1000, 32, 32, 3)\n",
      "训练集标签 shape:  (1000,)\n",
      "测试集数据 shape:  (100, 32, 32, 3)\n",
      "测试机标签 shape:  (100,)\n"
     ]
    }
   ],
   "source": [
    "# 初始化并加载数据\n",
    "\n",
    "import random\n",
    "import numpy as np\n",
    "from cs231n.data_utils import load_CIFAR10\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 这是 notebook 的 magic 命令，可以让 matplotlib 的图表\n",
    "# 显示在 notebook 中，而不是在一个新窗口里边\n",
    "%matplotlib inline\n",
    "# 设置图表的默认大小\n",
    "plt.rcParams['figure.figsize'] = (10.0, 8.0)\n",
    "plt.rcParams['image.interpolation'] = 'nearest'\n",
    "plt.rcParams['image.cmap'] = 'gray'\n",
    "\n",
    "# 还是一些 magic 命令，让 notebook 重载外部的 python 模块；\n",
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "\n",
    "# 加载原始 CIFAR-10 数据\n",
    "cifar10_dir = 'cs231n/datasets/cifar-10-batches-py'\n",
    "\n",
    "# 清理变量，以防多次加载数据（这可能会导致内存问题）\n",
    "try:\n",
    "   del X_train, y_train\n",
    "   del X_test, y_test\n",
    "   print('Clear previously loaded data.')\n",
    "except:\n",
    "   pass\n",
    "\n",
    "X_train, y_train, X_test, y_test = load_CIFAR10(cifar10_dir)\n",
    "\n",
    "# 作为练习，为了避免运行时间太长，这里再对数据进行采样，减小规模\n",
    "num_training = 1000\n",
    "mask = list(range(num_training))\n",
    "X_train = X_train[mask]\n",
    "y_train = y_train[mask]\n",
    "\n",
    "num_test = 100\n",
    "mask = list(range(num_test))\n",
    "X_test = X_test[mask]\n",
    "y_test = y_test[mask]\n",
    "print('训练集数据 shape: ', X_train.shape)\n",
    "print('训练集标签 shape: ', y_train.shape)\n",
    "print('测试集数据 shape: ', X_test.shape)\n",
    "print('测试机标签 shape: ', y_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "# 进行对原数据进行五中变换\n",
    "trans = ['减去公共均值', '减去像素均值', '减去公共均值然后除以公共标准差', '减去像素均值然后除以像素标准差', '旋转数据坐标轴']\n",
    "# 数据合并，方便一起变换\n",
    "X = np.r_[X_train, X_test]\n",
    "# 存放变换后结果\n",
    "Xs = []\n",
    "for i in range(5):\n",
    "    Xs.append(np.zeros(X.shape))\n",
    "# 三通道分开运算\n",
    "color_channel = ['R', 'G', 'B']\n",
    "for i in range(3):\n",
    "    # 单通道数据\n",
    "    single_channel = X[:, :, :, i]\n",
    "    # 公共均值\n",
    "    mean_pub = np.mean(single_channel)\n",
    "    # 像素均值\n",
    "    mean_pix = np.mean(single_channel, axis=0)\n",
    "    # 公共标准差\n",
    "    sd_pub = np.std(single_channel)\n",
    "    # 像素标准差\n",
    "    sd_pix = np.std(single_channel, axis=0)\n",
    "    \n",
    "    # 减去公共均值\n",
    "    Xs[0][:, :, :, i] = single_channel - mean_pub\n",
    "    # 减去像素均值\n",
    "    Xs[1][:, :, :, i] = single_channel - mean_pix\n",
    "    # 减去公共均值，然后除以公共标准差\n",
    "    Xs[2][:, :, :, i] = (single_channel - mean_pub) / sd_pub\n",
    "    # 减去像素均值，然后除以标准差\n",
    "    Xs[3][:, :, :, i] = (single_channel - mean_pix) / sd_pix\n",
    "    # 旋转数据的坐标轴\n",
    "    for j in range(X.shape[0]):\n",
    "        Xs[4][j, :, :, i] = np.rot90(single_channel[j, :])\n",
    "print()\n",
    "        \n",
    "# 重新把数据拆分成训练集和测试集\n",
    "X_trains = [None] * 5\n",
    "X_tests = [None] * 5\n",
    "X_trains_row = [None] * 5\n",
    "X_tests_row = [None] * 5\n",
    "for i in range(5):\n",
    "    X_trains[i] = Xs[i][:X_train.shape[0], :]\n",
    "    X_tests[i] = Xs[i][X_train.shape[0]:, :]\n",
    "    # 把图片数据变成一行\n",
    "    X_trains_row[i] = np.reshape(X_trains[i], (X_trains[i].shape[0], -1))\n",
    "    X_tests_row[i] = np.reshape(X_tests[i], (X_tests[i].shape[0], -1))\n",
    "# 原始图片数据也变成一行\n",
    "X_train_orign = np.reshape(X_train, (X_train.shape[0], -1))\n",
    "X_test_origin = np.reshape(X_test, (X_test.shape[0], -1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--- 原始数据 ---\n",
      "距离矩阵抽样：\n",
      "[[167664. 188615. 240781. 151553. 195597.]\n",
      " [299995. 242668. 178870. 303200. 250094.]\n",
      " [237506. 188165. 168501. 228323. 172019.]\n",
      " [247229. 192728. 209786. 272628. 226270.]\n",
      " [144398. 190163. 278613. 133155. 194883.]]\n",
      "预测结果:\n",
      "[4. 1. 8. 8. 6. 6. 6. 2. 0. 1. 8. 8. 4. 7. 4. 4. 7. 3. 8. 6. 4. 0. 2. 5.\n",
      " 4. 8. 6. 4. 6. 4. 0. 2. 4. 6. 9. 4. 2. 1. 4. 5. 0. 3. 0. 6. 8. 8. 6. 0.\n",
      " 4. 2. 8. 0. 6. 0. 8. 8. 5. 3. 4. 4. 4. 5. 4. 0. 4. 2. 8. 2. 6. 9. 2. 5.\n",
      " 0. 8. 0. 2. 7. 3. 5. 0. 8. 3. 2. 0. 0. 2. 3. 4. 8. 8. 8. 4. 8. 8. 4. 4.\n",
      " 6. 0. 3. 7.]\n"
     ]
    }
   ],
   "source": [
    "from cs231n.classifiers import KNearestNeighbor\n",
    "\n",
    "# 创建 KNN 分类器实例\n",
    "# 注意训练 KNN 分类器其实什么也没干，分类器只是简单地记录了一下数据\n",
    "classifier = KNearestNeighbor()\n",
    "classifier.train(X_train_orign, y_train)\n",
    "dists_origin = classifier.compute_distances_l1(X_test_origin)\n",
    "y_test_pred_origin = classifier.predict_labels(dists_origin, k=1)\n",
    "print(\"--- 原始数据 ---\")\n",
    "print(\"距离矩阵抽样：\")\n",
    "print(dists_origin[:5,:5])\n",
    "print(\"预测结果:\")\n",
    "print(y_test_pred_origin)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--- 减去公共均值 ---\n",
      "距离矩阵抽样：\n",
      "[[167664. 188615. 240781. 151553. 195597.]\n",
      " [299995. 242668. 178870. 303200. 250094.]\n",
      " [237506. 188165. 168501. 228323. 172019.]\n",
      " [247229. 192728. 209786. 272628. 226270.]\n",
      " [144398. 190163. 278613. 133155. 194883.]]\n",
      "预测结果:\n",
      "[4. 1. 8. 8. 6. 6. 6. 2. 0. 1. 8. 8. 4. 7. 4. 4. 7. 3. 8. 6. 4. 0. 2. 5.\n",
      " 4. 8. 6. 4. 6. 4. 0. 2. 4. 6. 9. 4. 2. 1. 4. 5. 0. 3. 0. 6. 8. 8. 6. 0.\n",
      " 4. 2. 8. 0. 6. 0. 8. 8. 5. 3. 4. 4. 4. 5. 4. 0. 4. 2. 8. 2. 6. 9. 2. 5.\n",
      " 0. 8. 0. 2. 7. 3. 5. 0. 8. 3. 2. 0. 0. 2. 3. 4. 8. 8. 8. 4. 8. 8. 4. 4.\n",
      " 6. 0. 3. 7.]\n",
      "错误数量：\n",
      "0\n",
      "--- 减去像素均值 ---\n",
      "距离矩阵抽样：\n",
      "[[167664. 188615. 240781. 151553. 195597.]\n",
      " [299995. 242668. 178870. 303200. 250094.]\n",
      " [237506. 188165. 168501. 228323. 172019.]\n",
      " [247229. 192728. 209786. 272628. 226270.]\n",
      " [144398. 190163. 278613. 133155. 194883.]]\n",
      "预测结果:\n",
      "[4. 1. 8. 8. 6. 6. 6. 2. 0. 1. 8. 8. 4. 7. 4. 4. 7. 3. 8. 6. 4. 0. 2. 5.\n",
      " 4. 8. 6. 4. 6. 4. 0. 2. 4. 6. 9. 4. 2. 1. 4. 5. 0. 3. 0. 6. 8. 8. 6. 0.\n",
      " 4. 2. 8. 0. 6. 0. 8. 8. 5. 3. 4. 4. 4. 5. 4. 0. 4. 2. 8. 2. 6. 9. 2. 5.\n",
      " 0. 8. 0. 2. 7. 3. 5. 0. 8. 3. 2. 0. 0. 2. 3. 4. 8. 8. 8. 4. 8. 8. 4. 4.\n",
      " 6. 0. 3. 7.]\n",
      "错误数量：\n",
      "0\n",
      "--- 减去公共均值然后除以公共标准差 ---\n",
      "距离矩阵抽样：\n",
      "[[2622.5199068  2948.83305993 3755.26646236 2367.82043442 3046.33123532]\n",
      " [4685.34883017 3805.00277477 2798.65350467 4735.71787809 3933.2892327 ]\n",
      " [3710.62297033 2950.7726085  2637.97302679 3561.30944201 2703.54836047]\n",
      " [3847.15822386 3013.16572967 3283.17393851 4249.63235359 3547.72840748]\n",
      " [2264.24921322 2978.36542969 4372.1322545  2089.13852764 3051.40404182]]\n",
      "预测结果:\n",
      "[4. 1. 8. 8. 6. 6. 6. 2. 0. 1. 8. 8. 4. 7. 4. 4. 7. 3. 8. 6. 4. 0. 2. 5.\n",
      " 4. 8. 6. 4. 6. 4. 0. 2. 4. 6. 9. 4. 2. 1. 4. 5. 0. 3. 0. 6. 8. 8. 6. 0.\n",
      " 4. 2. 8. 0. 6. 3. 8. 8. 5. 3. 4. 4. 4. 5. 4. 0. 4. 2. 8. 2. 6. 9. 2. 5.\n",
      " 0. 8. 0. 2. 7. 3. 5. 0. 8. 3. 2. 0. 0. 2. 3. 4. 8. 8. 8. 4. 8. 8. 4. 4.\n",
      " 6. 0. 3. 7.]\n",
      "错误数量：\n",
      "1\n",
      "--- 减去像素均值然后除以像素标准差 ---\n",
      "距离矩阵抽样：\n",
      "[[2711.94719928 3011.54804618 3708.40751042 2427.94088281 3084.12996028]\n",
      " [4662.7492914  3825.01458438 2904.95717707 4689.33523149 3997.14624722]\n",
      " [3672.09551942 2961.20069215 2706.46696702 3494.96593444 2745.19971087]\n",
      " [3863.04317949 3050.89650045 3365.00141634 4261.73711061 3658.60901483]\n",
      " [2317.5550555  3017.12853825 4315.707833   2146.88710691 3076.74288075]]\n",
      "预测结果:\n",
      "[4. 1. 8. 8. 6. 6. 6. 2. 0. 1. 8. 8. 4. 7. 4. 4. 7. 3. 8. 6. 4. 0. 2. 5.\n",
      " 2. 8. 6. 4. 6. 4. 0. 2. 4. 6. 9. 4. 2. 1. 4. 5. 0. 3. 0. 6. 8. 8. 6. 0.\n",
      " 4. 2. 8. 0. 6. 3. 8. 8. 5. 3. 4. 4. 4. 5. 4. 0. 4. 2. 8. 2. 6. 9. 2. 6.\n",
      " 0. 8. 0. 2. 7. 3. 2. 0. 8. 3. 2. 0. 0. 2. 3. 4. 8. 8. 8. 4. 8. 8. 4. 4.\n",
      " 6. 0. 3. 7.]\n",
      "错误数量：\n",
      "4\n",
      "--- 旋转数据坐标轴 ---\n",
      "距离矩阵抽样：\n",
      "[[167664. 188615. 240781. 151553. 195597.]\n",
      " [299995. 242668. 178870. 303200. 250094.]\n",
      " [237506. 188165. 168501. 228323. 172019.]\n",
      " [247229. 192728. 209786. 272628. 226270.]\n",
      " [144398. 190163. 278613. 133155. 194883.]]\n",
      "预测结果:\n",
      "[4. 1. 8. 8. 6. 6. 6. 2. 0. 1. 8. 8. 4. 7. 4. 4. 7. 3. 8. 6. 4. 0. 2. 5.\n",
      " 4. 8. 6. 4. 6. 4. 0. 2. 4. 6. 9. 4. 2. 1. 4. 5. 0. 3. 0. 6. 8. 8. 6. 0.\n",
      " 4. 2. 8. 0. 6. 0. 8. 8. 5. 3. 4. 4. 4. 5. 4. 0. 4. 2. 8. 2. 6. 9. 2. 5.\n",
      " 0. 8. 0. 2. 7. 3. 5. 0. 8. 3. 2. 0. 0. 2. 3. 4. 8. 8. 8. 4. 8. 8. 4. 4.\n",
      " 6. 0. 3. 7.]\n",
      "错误数量：\n",
      "0\n"
     ]
    }
   ],
   "source": [
    "for i in range(5):\n",
    "    classifier.train(X_trains_row[i], y_train)\n",
    "    dists = classifier.compute_distances_l1(X_tests_row[i])\n",
    "    y_test_pred = classifier.predict_labels(dists, k=1)\n",
    "    print(\"--- %s ---\" % trans[i])\n",
    "    print(\"距离矩阵抽样：\")\n",
    "    print(dists[:5,:5])\n",
    "    print(\"预测结果:\")\n",
    "    print(y_test_pred)\n",
    "    print(\"错误数量：\")\n",
    "    print(np.sum(y_test_pred != y_test_pred_origin))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
